package com.dana1.nos;

import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.List;

import org.apache.commons.collections.IteratorUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import com.dana1.nos.storage.MemoryStorage;
import com.dana1.nos.util.MetaSupport;
import com.dana1.nos.util.MetaSupport.MetaKey;

public class TestMemoryStorage {

	transient MemoryStorage storage;
	
	
	@Before
	public void setup()
	{
		storage = new MemoryStorage();
	}
	
	@Test
	public void testStandardGetPut() {

		StringBuilder sa = new StringBuilder("This is a test");
		
		storage.put("a", sa);

		StringBuilder sb = storage.get(StringBuilder.class,"a");
		
		Assert.assertEquals("This is a test", sb.toString());
		Assert.assertNotSame(sa,sb);

		storage.remove(sa);
		
		storage.put("a", sa); // insert works after remove?

		storage.put(null, sa.reverse()); // null identifier should be ok, once object is recognized
		 
	}

	@Test(expected=ConcurrentModificationException.class)
	public void testConcurrencyFail() {

		StringBuilder sa = new StringBuilder("This is a test");
		
		storage.put("a", sa);

		StringBuilder sb = storage.get(StringBuilder.class,"a");
		
		storage.put("a", sa.reverse());
		
		storage.put("a", sb.reverse()); // same string, but now not the most recent copy
		
	}

	@Test(expected=IllegalArgumentException.class)
	public void testIdentChangeFails()
	{
		StringBuilder sa = new StringBuilder("This is a test");
		
		storage.put("a", sa);
		
		storage.put("b", sa);
	}

	@Test(expected=ConcurrentModificationException.class)
	public void testDuplicateRemoveFails()
	{
		StringBuilder sa = new StringBuilder("This is a test");
		
		storage.put("a", sa);
		
		StringBuilder sb = storage.get(StringBuilder.class, "a");

		storage.remove(sa);
		
		storage.remove(sb);
	}
	
	@Test
	public void testThatGetReturnsDifferentItems()
	{
		StringBuilder sa = new StringBuilder("This is a test");
		
		storage.put("a", sa);
		
		StringBuilder s1 = storage.get(StringBuilder.class,"a");
		
		StringBuilder s2 = storage.get(StringBuilder.class,"a");
		
		Assert.assertNotSame(s1, s2);
	}

	MetaKey<String> metaKey = new MetaKey<>("A String");
	
	
	@Test
	public void testThatMetaDoesntPersistThruStorage()
	{
		StringBuilder sa = new StringBuilder("This is a test");
		
		MetaSupport.meta(sa, metaKey, "Doh");
		
		storage.put("a", sa);
		
		StringBuilder s1 = storage.get(StringBuilder.class,"a");
		
		Assert.assertNull(MetaSupport.meta(s1, metaKey));

	}

	@Test
	public void testByPrefix()
	{
		storage.put("a", new String("a"));
		storage.put("a a", new String("a a"));
		storage.put("aa", new String("aa"));
		storage.put("aa ", new String("aa "));
		storage.put("aa a", new String("aa a"));
		storage.put("aa Z", new String("aa Z"));
		storage.put("aaa", new String("aaa"));
		storage.put("aaz", new String("aaz"));
		storage.put("az a", new String("az a"));
		storage.put("ab a", new String("ab a"));
		storage.put("b a", new String("b a"));
		
		Assert.assertEquals(0, storage.countByPrefix(String.class, ""));
		Assert.assertEquals(6, storage.countByPrefix(String.class, "aa"));
		Assert.assertEquals(1, storage.countByPrefix(String.class, "a "));
		Assert.assertEquals(10, storage.countByPrefix(String.class, "a"));
		Assert.assertEquals(3, storage.countByPrefix(String.class, "aa "));
		
		List<String> l = IteratorUtils.toList(storage.getByPrefix(String.class, "aa "));

		Collections.sort(l,String.CASE_INSENSITIVE_ORDER);
		
		Assert.assertEquals(3,l.size());
		Assert.assertEquals("aa ",l.get(0));
		Assert.assertEquals("aa a",l.get(1));
		Assert.assertEquals("aa Z",l.get(2));
	
	}

}
